/*
 * Copyright 2020-2030 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.minimalismstyle.fresh.oss.service.impl

import com.gitee.minimalismstyle.fresh.common.core.domain.*
import com.gitee.minimalismstyle.fresh.common.core.extra.copyProperties
import com.gitee.minimalismstyle.fresh.oss.api.model.OssFile
import com.gitee.minimalismstyle.fresh.oss.dao.OssFileDao
import com.gitee.minimalismstyle.fresh.oss.api.service.OssFileService
import com.gitee.minimalismstyle.fresh.oss.config.OssProperties
import com.gitee.minimalismstyle.fresh.oss.store.StoreFactory
import feign.Response
import org.apache.commons.beanutils.BeanUtils
import org.apache.commons.codec.digest.DigestUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.io.OutputStream
import kotlin.streams.toList

@Primary
@Service
class OssFileServiceImpl : OssFileService {
    @Autowired
    private lateinit var ossFileDao: OssFileDao
    @Autowired
    private lateinit var ossProperties: OssProperties
    @Autowired
    private lateinit var snowflakeIdWorker: SnowflakeIdWorker

    @Transactional
    override fun save(file: MultipartFile): R<OssFile> {

        val batchId = snowflakeIdWorker.nextId()// 生成批次号
        return save(file, batchId)
    }

    @Transactional
    override fun save(file: MultipartFile, batchId: Long): R<OssFile> {
        val store = StoreFactory.getStore(ossProperties.store)// 获取仓库

        val ossFile = newOssFile(file)
        ossFile.batchId = batchId

        file.inputStream.use {// 将文件保存到仓库
            ossFile.path = store.write(ossFile, file.inputStream)
        }

        // 保存文件信息
        ossFileDao.insert(ossFile)
        return R.success(ossFile)
    }

    @Transactional
    override fun saveBatch(files: List<MultipartFile>, batchId: Long): R<List<OssFile>> {
        val store = StoreFactory.getStore(ossProperties.store)// 获取仓库

        val ossFiles: MutableList<OssFile> = arrayListOf()
        // 将文件保存到仓库
        files.forEach { file ->
            val ossFile = newOssFile(file)
            ossFile.batchId = batchId
            file.inputStream.use {
                ossFile.path = store.write(ossFile, file.inputStream)
            }
            ossFiles.add(ossFile)
        }
        // 保存文件信息
        ossFileDao.insertAll(ossFiles)
        return R.success(ossFiles)
    }

    @Transactional
    override fun saveBatch(files: List<MultipartFile>): R<List<OssFile>> {
        val batchId = snowflakeIdWorker.nextId()// 生成批次号
        return saveBatch(files, batchId)
    }

    override fun findById(id: Long): R<OssFile> {
        return R.success(ossFileDao.findById(id).copyProperties(OssFile::class))
    }

    override fun findByBatchId(batchId: Long): R<List<OssFile>> {
        return R.success(ossFileDao.findByBatchId(batchId))
    }

    @Transactional
    override fun deleteById(id: Long): R<Int> {
        val ossFile = ossFileDao.findById(id)
        val store = StoreFactory.getStore(ossFile.store!!)

        // 删除文件
        store.delete(ossFile.path!!)
        // 删除文件信息
        var sum = ossFileDao.deleteById(id)
        return R.success(sum)
    }

    @Transactional
    override fun deleteByBatchId(batchId: Long): R<Int> {
        val ossFiles = ossFileDao.findByBatchId(batchId)
        val store = StoreFactory.getStore(ossFiles[0].store!!)
        // 删除文件
        ossFiles.forEach { ossFile ->
            store.delete(ossFile.path!!)
        }
        // 删除文件信息
        var sum = ossFileDao.deleteByBatchId(batchId)
        return R.success(sum)
    }

    override fun read(id: Long, os: OutputStream) {
        val ossFile = ossFileDao.findById(id)
        val store = StoreFactory.getStore(ossFile.store!!)
        store.read(ossFile, os)
    }

    override fun findByQueryParams(params: QueryParams<Simple>): R<QueryBody<Simple>> {
        val queryBody = ossFileDao.findByQueryParams(params)
        return R.success(queryBody)
    }

    override fun upload(file: MultipartFile): R<Map<String, Any>> {
        val ossFile = save(file)
        val map = mutableMapOf<String, Any>()
        BeanUtils.populate(ossFile, map)
        return R.success(map)
    }

    override fun getResponse(id: Long): Response {
        val ossFile = ossFileDao.findById(id)
        val store = StoreFactory.getStore(ossFile.store!!)
        val builder = Response.builder()
        store.read(ossFile).use {
            Response.builder().body(it, ossFile.size!!.toInt())
        }

        return builder.build()
    }

    /**
     * 根据MultipartFile对象获取文件信息
     * @param file
     * @return
     */
    private fun newOssFile(file: MultipartFile): OssFile{
        val ossFile = OssFile()
        ossFile.name = file.originalFilename
        ossFile.size = file.size
        ossFile.store = ossProperties.store
        ossFile.contentType = file.contentType
        ossFile.extName = file.originalFilename!!.substringAfter(".")
        ossFile.md5 = DigestUtils.md5Hex(file.bytes)
        return ossFile
    }
}